from datetime import datetime
import darkdetect
import sys
from PySide6.QtWidgets import * # type: ignore
from PySide6.QtCore import * # type: ignore
from PySide6.QtGui import * # type: ignore
from qfluentwidgets import *  # type: ignore

from gui.settings import SettingsWindow
from utils import cfg_util, windows_util
from utils.deepseek_util import DeepseekClient, RequestType
from utils.keyboard_util import addKeyboardListener
from utils.logger import Logger
import time
from utils import uiAccess_util
from utils.smooth_util import AnimatedColor, AnimatedPoint, AnimatedValue
from utils.dark_util import DarkModeDetector
from values.island_status import IslandStatus

logger = Logger('Island')

def print(obj: object) -> None:
    '''Custom print function that uses logger'''
    logger.logInfo(str(obj))

class Island(QWidget):
    '''Main dynamic island window class'''
    
    def __init__(self):
        start_time = time.perf_counter()
        super().__init__()
        
        # Set window properties for floating effect
        self.setWindowFlags(
            self.windowFlags() |
            Qt.WindowType.FramelessWindowHint |  # No window frame
            Qt.WindowType.WindowStaysOnTopHint |  # Always on top
            Qt.WindowType.Tool  # Minimal taskbar presence
        )
        self.setAttribute(
            Qt.WidgetAttribute.WA_TranslucentBackground,  # Transparent background
            True
        )
        self.resize(QApplication.primaryScreen().size().width(), 25)  # Full width, small height
        self.show()

        # Request UI Access after short delay
        QTimer.singleShot(500, lambda: self.getTop())

        # Animation timer for smooth updates
        timer = QTimer(self)
        timer.timeout.connect(self.repaint)
        timer.start(1000 // cfg_util.config_instance.fps)  # Use configured FPS

        # Animation controllers for smooth transitions
        animation_time = 500
        self.draw_width = AnimatedValue(animation_time, True)    # Width animation
        self.draw_height = AnimatedValue(animation_time, True)   # Height animation  
        self.bg_radius = AnimatedValue(animation_time, False)    # Corner radius animation
        self.offset_x = AnimatedValue(animation_time, True)      # Horizontal position
        self.text_cursor = AnimatedPoint(1000, True)   # Cursor position

        is_dark = darkdetect.isDark()

        self.bg_color = AnimatedColor(1000)                           # Background color
        self.bg_color.target_color = QColor(0, 0, 0, 245) if is_dark else QColor(255, 255, 255, a=190)

        self.font_color = AnimatedColor(1000)
        self.font_color.target_color = QColor(255, 255, 255) if is_dark else QColor(0, 0, 0)

        self.status = IslandStatus.IDLE  # Current island state
        
        # Create control buttons widget
        self.hovering_widget = QWidget()
        layout = QVBoxLayout()
        
        close_btn = PushButton('Close')
        close_btn.clicked.connect(lambda: sys.exit(0))
        layout.addWidget(close_btn)
        
        settings_btn = PushButton('Settings')
        settings_btn.clicked.connect(self.launch_settings)
        layout.addWidget(settings_btn)
        
        about_btn = PushButton('About')
        about_btn.clicked.connect(lambda: print('About clicked'))
        layout.addWidget(about_btn)
        
        self.hovering_widget.setLayout(layout)

        # Main layout
        global_layout = QHBoxLayout()
        global_layout.addWidget(self.hovering_widget)
        self.hovering_widget.hide()  # Hidden by default
        self.setLayout(global_layout)

        # Settings window (created but hidden)
        self.setting_window = SettingsWindow()
        self.setting_window.hide()

        # Variables
        self.dark_listener = DarkModeDetector(self)
        self.dark_listener.dark_changed.connect(self.darkModeChanged)

        self.inputed_texts = ''

        self.is_dark = darkdetect.isDark()

        self.deepseek_client = DeepseekClient(cfg_util.config_instance.api_key)
        self.ai_completing = False

        # Hot key
        addKeyboardListener('Shift+Alt+Z', self.startTextInput)
        
        self.active_window_title = ''

        print(f'Island initialized took in {time.perf_counter() - start_time:.4f}s')

    def chatCallback(self, type: RequestType, content: str):
        if type == RequestType.STARTING:
            self.inputed_texts = ''
            self.status = IslandStatus.INPUTING
            self.ai_completing = True
        elif type == RequestType.COMPLETING:
            self.inputed_texts += content
        elif type == RequestType.COMPLETED:
            self.ai_completing = False

    def startTextInput(self):
        self.status = IslandStatus.INPUTING
        self.inputed_texts = ''
        return False

    def darkModeChanged(self, dark: bool):
        self.bg_color.target_color = QColor(0, 0, 0, 245) if dark else QColor(255, 255, 255, 190)
        self.font_color.target_color = QColor(255, 255, 255) if dark else QColor(0, 0, 0)

        setTheme(Theme.DARK if dark else Theme.LIGHT)

    def launch_settings(self) -> None:
        '''Show settings window'''
        self.setting_window.show()

    def paintEvent(self, event: QPaintEvent) -> None:
        '''Handle window painting and animations'''
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)  # Smooth edges

        self.drawBackground(painter)  # Draw island background
        self.drawTexts(painter)       # Draw time text
        self.resetPosition()          # Update window position

        self.is_dark = darkdetect.isDark()

        return super().paintEvent(event)
    
    def drawTexts(self, painter: QPainter) -> None:
        '''Draw text content on the island'''
        if self.status != IslandStatus.IDLE and self.status != IslandStatus.INPUTING:
            return  # Only show time in idle or inputing state

        if self.status == IslandStatus.IDLE:
            time_text = datetime.now().strftime('%H:%M')
        elif self.status == IslandStatus.INPUTING:
            time_text = self.inputed_texts
        else:
            time_text = 'Unknown...Maybe a bug?'
        font = QFont(cfg_util.config_instance.font, 16)
        font_metrics = QFontMetrics(font)
        
        painter.setPen(self.font_color.current_color)  # White text
        painter.setFont(font)
        
        # Center text horizontally and vertically
        painter.drawText(QPoint(int((self.draw_width.current_value - font_metrics.horizontalAdvance(time_text)) / 2) - 5,
                                int((self.height() - font_metrics.boundingRect(time_text).height()) + font_metrics.capHeight())), time_text)

        self.text_cursor.target_point = QPoint(
            int((self.draw_width.current_value + font_metrics.horizontalAdvance(time_text)) / 2) + (3 if self.inputed_texts else 0),
            (self.height() - font_metrics.boundingRect(time_text).height()) // 2
        )
        
        if self.status == IslandStatus.INPUTING and self.inputed_texts:
            # draw inputing line
            painter.setPen(QPen(QColor(255, 255, 255) if self.is_dark else QColor(0, 0, 0), 2))
            painter.drawLine(
                self.text_cursor.current_point,
                self.text_cursor.current_point + QPoint(0, font_metrics.boundingRect(time_text).height())
            )
        
        if self.status == IslandStatus.IDLE:  # Shrink text when idle
            self.draw_width.target_value = font_metrics.horizontalAdvance(time_text) + 50
        elif self.status == IslandStatus.INPUTING:
            self.draw_width.target_value = font_metrics.horizontalAdvance(time_text) + 100
    
    def drawBackground(self, painter: QPainter) -> None:
        '''Draw the dynamic island background with smooth animations'''
        rect = QRectF(0, 0, self.draw_width.current_value, self.height())

        # Update animation targets based on current state
        if self.status == IslandStatus.IDLE:
            self.bg_radius.target_value = self.height() // 2  # Rounded pill shape
            self.draw_height.target_value = 35                # Small height
            self.draw_height.extra_animation = True           # Enable bounce
        elif self.status == IslandStatus.HOVERING:
            self.bg_radius.target_value = 25                  # Slightly rounded
            self.draw_width.target_value = self.hovering_widget.sizeHint().width() + 150  # Expand for content
            self.draw_height.target_value = self.hovering_widget.sizeHint().height() + 20
            self.draw_height.extra_animation = False          # No bounce when expanding
        elif self.status == IslandStatus.INPUTING:
            self.bg_radius.target_value = self.height() // 2  # Rounded pill shape
            self.draw_height.target_value = 45                # Taller height for texts
            self.draw_height.extra_animation = True           # Enable bounce
            self.raise_()

        self.bg_radius.target_value = max(self.height() // 2, self.bg_radius.target_value)

        # Update window size based on current state
        self.resize(
            int(self.draw_width.current_value),
            int(self.draw_height.current_value)
        )

        # Create rounded rectangle pathz
        path = QPainterPath()
        path.addRoundedRect(rect, self.bg_radius.current_value, self.bg_radius.current_value)

        # Fill with semi-transparent black
        painter.fillPath(path, self.bg_color.current_color)
    
    def resetPosition(self) -> None:
        '''Center the island horizontally and position vertically with offset'''
        screen_size = QApplication.primaryScreen().size().toTuple()
        self.offset_x.target_value = (screen_size[0] - int(self.draw_width.current_value)) // 2
        
        # Position window with smooth animation
        self.move(
            int(self.offset_x.current_value),
            cfg_util.config_instance.island_height_offset
        )

    def keyPressEvent(self, event: QKeyEvent) -> None:
        if self.ai_completing:
            return super().keyPressEvent(event)
        if self.status == IslandStatus.INPUTING:
            if event.key() == Qt.Key.Key_Return:
                self.deepseek_client.chatComplete(self.inputed_texts, self.chatCallback)
            elif event.key() == Qt.Key.Key_Backspace:
                self.inputed_texts = self.inputed_texts[:-1]
                event.ignore()
            elif event.key() == Qt.Key.Key_Escape:
                self.status = IslandStatus.IDLE
            else:
                self.inputed_texts += event.text()
                event.ignore()

        return super().keyPressEvent(event)

    def enterEvent(self, event: QEnterEvent) -> None:
        '''Handle mouse entering the island - expand to show controls'''
        if self.status != IslandStatus.INPUTING:
            self.status = IslandStatus.HOVERING
            self.hovering_widget.show()
        return super().enterEvent(event)
    
    def leaveEvent(self, event: QEvent) -> None:
        '''Handle mouse leaving the island - collapse to compact state'''
        if self.status != IslandStatus.INPUTING:
            self.status = IslandStatus.IDLE
            self.hovering_widget.hide()
        return super().leaveEvent(event)

    def getTop(self) -> None:
        '''Request UI Access privileges for better pinning effect'''
        if windows_util.isAdminMode():
            uiAccess_util.getUIAccess(self)
            print('UI Access granted')
        else:
            # Fallback to standard always-on-top
            self.setWindowFlags(
                self.windowFlags() |
                Qt.WindowType.WindowStaysOnTopHint
            )
            print('UI Access granting skipped')